bitkeeper revision 1.1236.24.1 (42307336-2YsfyDrGECB7J1MGcn3zg)
authormwilli2@equilibrium.research <mwilli2@equilibrium.research>
Thu, 10 Mar 2005 16:17:58 +0000 (16:17 +0000)
committermwilli2@equilibrium.research <mwilli2@equilibrium.research>
Thu, 10 Mar 2005 16:17:58 +0000 (16:17 +0000)
Fix malloc / ring full checking (thanks to Harry Butterworth for spotting these).
Add more locking (fixes a potential race on 2.4, also needed for safety now we
can do SMP).

Signed-off-by: <mark.williamson@cl.cam.ac.uk>
linux-2.6.10-xen-sparse/drivers/xen/usbfront/usbfront.c
linux-2.6.10-xen-sparse/drivers/xen/usbfront/xhci.h

index 46cca3058afed462943b1e99dd655094deb198e1..3c153d909d6148cb673e345a3fc314ecadb27dc0 100644 (file)
@@ -203,6 +203,7 @@ static int xhci_construct_isoc(usbif_request_t *req, struct urb *urb)
  */
 static int xhci_queue_req(struct urb *urb)
 {
+        unsigned long flags;
         usbif_request_t *req;
         usbif_front_ring_t *usb_ring = &xhci->usb_ring;
 
@@ -213,11 +214,13 @@ static int xhci_queue_req(struct urb *urb)
                usbif->resp_prod, xhci->usb_resp_cons);
 #endif
         
+        spin_lock_irqsave(&xhci->ring_lock, flags);
 
         if ( RING_FULL(usb_ring) )
         {
                 printk(KERN_WARNING
                        "xhci_queue_req(): USB ring full, not queuing request\n");
+                spin_unlock_irqrestore(&xhci->ring_lock, flags);
                 return -ENOBUFS;
         }
 
@@ -253,6 +256,8 @@ static int xhci_queue_req(struct urb *urb)
         usb_ring->req_prod_pvt++;
         RING_PUSH_REQUESTS(usb_ring);
 
+        spin_unlock_irqrestore(&xhci->ring_lock, flags);
+
        notify_via_evtchn(xhci->evtchn);
 
         DPRINTK("Queued request for an URB.\n");
@@ -276,11 +281,15 @@ static inline usbif_request_t *xhci_queue_probe(usbif_vdev_t port)
                virt_to_machine(&usbif->req_prod),
               usbif->resp_prod, xhci->usb_resp_cons);
 #endif
-        
+        /* This is always called from the timer interrupt. */
+        spin_lock(&xhci->ring_lock);
+       
         if ( RING_FULL(usb_ring) )
         {
                 printk(KERN_WARNING
                        "xhci_queue_probe(): ring full, not queuing request\n");
+                spin_unlock(&xhci->ring_lock);
                 return NULL;
         }
 
@@ -295,6 +304,8 @@ static inline usbif_request_t *xhci_queue_probe(usbif_vdev_t port)
         usb_ring->req_prod_pvt++;
         RING_PUSH_REQUESTS(usb_ring);
 
+        spin_unlock(&xhci->ring_lock);
+
        notify_via_evtchn(xhci->evtchn);
 
         return req;
@@ -308,6 +319,17 @@ static int xhci_port_reset(usbif_vdev_t port)
         usbif_request_t *req;
         usbif_front_ring_t *usb_ring = &xhci->usb_ring;
 
+        /* Only ever happens from process context (hub thread). */
+        spin_lock_irq(&xhci->ring_lock);
+
+        if ( RING_FULL(usb_ring) )
+        {
+                printk(KERN_WARNING
+                       "xhci_port_reset(): ring full, not queuing request\n");
+                spin_unlock_irq(&xhci->ring_lock);
+                return -ENOBUFS;
+        }
+
         /* We only reset one port at a time, so we only need one variable per
          * hub. */
         xhci->awaiting_reset = 1;
@@ -323,6 +345,8 @@ static int xhci_port_reset(usbif_vdev_t port)
         usb_ring->req_prod_pvt++;
        RING_PUSH_REQUESTS(usb_ring);
 
+        spin_unlock_irq(&xhci->ring_lock);
+
        notify_via_evtchn(xhci->evtchn);
 
         while ( xhci->awaiting_reset > 0 )
@@ -1529,6 +1553,10 @@ static void usbif_status_change(usbif_fe_interface_status_changed_t *status)
        xhci->rh.numports = status->num_ports;
 
         xhci->rh.ports = kmalloc (sizeof(xhci_port_t) * xhci->rh.numports, GFP_KERNEL);
+       
+       if ( xhci->rh.ports == NULL )
+            goto alloc_ports_nomem;
+       
         memset(xhci->rh.ports, 0, sizeof(xhci_port_t) * xhci->rh.numports);
 
        usb_connect(xhci->rh.dev);
@@ -1553,7 +1581,7 @@ static void usbif_status_change(usbif_fe_interface_status_changed_t *status)
                 xhci->evtchn, xhci->irq);
 
         xhci->state = USBIF_STATE_CONNECTED;
-        
+
         break;
 
     default:
@@ -1561,6 +1589,12 @@ static void usbif_status_change(usbif_fe_interface_status_changed_t *status)
                status->status);
         break;
     }
+
+    return;
+
+ alloc_ports_nomem:
+    printk(KERN_WARNING "Failed to allocate port memory, XHCI failed to connect.\n");
+    return;
 }
 
 /**
index f503e59ebc3bcd1a2f57dcc1bc2ac6b35471ba21..b6df9ccf63aaa59085c86b14baefddf0feec4582 100644 (file)
@@ -74,6 +74,7 @@ struct xhci {
 
        struct virt_root_hub rh;        /* private data of the virtual root hub */
 
+        spinlock_t ring_lock;
         usbif_front_ring_t usb_ring;
 
         int awaiting_reset;